home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 31
/
Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso
/
Aminet
/
dev
/
c
/
cflow.lha
/
cflow-2.0
/
prcg.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-02-20
|
14KB
|
505 lines
/* This file contains code for building and printing a directed cyclic
* graph as part of the cflow program. */
/* Author: M.M. Taylor, DCIEM, Toronto, Canada.
* 22/Jan/81, Alexis Kwan (HCR at DCIEM).
* 12-Jun-84, Kevin Szabo
* 8/8/84, Tony Hansen, AT&T-IS, pegasus!hansen.
*
* This file is contributed to the public domain by Andrew Moore of
* Talke Studio */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "prcg.prototypes.h"
#ifndef PATH_MAX
#define PATH_MAX 1024 /* max pathname length */
#endif
#ifndef NAME_MAX
#define NAME_MAX 32
#endif
#define BUF_MAX (NAME_MAX * 2 + PATH_MAX + 20) /* max line buffer length */
#define DEPTH_MAX 200 /* max path length */
#define TABSIZE 8 /* tab size */
#define MARGIN 20 /* right margin of paper */
#define PAPERWIDTH (14*TABSIZE + MARGIN) /* tabbing limits */
#ifndef __P
#ifndef __STDC__
#define __P(proto) ()
#else
#define __P(proto) proto
#endif
#endif
/* name list node */
struct name_node {
struct name_node *next; /* next name list node */
struct imm_node *imm_list; /* node's immediate list */
long name_visited; /* set if node previously visited */
int is_arc_head; /* set if node is an arc head */
char *imm_name; /* name of first imm_list node */
char *imm_ref; /* reference to first imm_list node */
};
/* immediate list node */
struct imm_node {
struct imm_node *next; /* next immediate list node */
struct name_node *name_node_p; /* node's name node pointer */
};
/* The name list (nlist) contains names (e.g., function/variable) in
* lexicographical order. Each name node has its own list (imm_list) of
* immediates (e.g., callers/callees). The immediate nodes do not
* themselves have names; instead, each node has a pointer to its name
* (node) in the name list. The nodes and pointers form the vertices and
* edges, respectively, of a directed cyclic graph (DCG).
*
* The prcg program builds a DCG by inserting names pairs from the input
* as arcs into the graph. Printing the DCG is done by a preorder
* traversal from a root name node. Paths are defined by the immediate
* list of the root name node, and, recursively, by the immediate lists
* of its immediates. */
/* where is this initialized? */
static struct name_node *nlist;
static char *dashes; /* separators for deep nestings */
/* The following options are available :
*
* -a print a separate graph for each name (default: no)
* -d nn print graphs to at most depth `nn' (default: 200)
* -r root print graph only for `root' (default: each root name)
* -x print each sub-graph in full (default: no)
* -w nn print graph to fit in `nn' columns (default: 132 columns) */
/* option flags */
static int graph_all = 0; /* print a graph for each name */
static int maxdepth = DEPTH_MAX; /* print to at most depth `maxdepth' */
static int expand_all = 0; /* print each sub-graph in full */
static int ntabs = ((PAPERWIDTH - MARGIN) / TABSIZE); /* how wide to go */
static int select_roots = 0; /* print graph for selected names */
static char *arglist = "ad:r:ixw:"; /* valid options */
static char *progname; /* argv[0] */
extern char *optarg;
extern int optind;
static void usage(void)
{
fprintf(stderr, "Usage: %s [-ax ] [-d depth] [-r root]\n", progname);
exit(1);
}
main(int argc, char **argv)
{
int c, i;
int width = PAPERWIDTH;
progname = argv[0];
while ((c = getopt(argc, argv, arglist)) != EOF)
switch (c) {
case 'a':
graph_all = 1;
break;
case 'd':
if ((maxdepth = atoi(optarg)) > DEPTH_MAX)
maxdepth = DEPTH_MAX;
break;
case 'i':
expand_all = 1;
graph_all = 1;
maxdepth = 2;
break;
case 'r':
select_roots = 1;
break;
case 'w':
if ((width = atoi(optarg)) <= 0)
width = PAPERWIDTH;
break;
case 'x':
expand_all = 1;
break;
case '?':
default:
usage();
}
ntabs = (width - MARGIN) / TABSIZE;
build_dcg();
print_dcg(argc, argv);
exit(0);
}
/* Name pairs in the input are expected in blocks of the form:
*
* name1a --> name2aa
* name1a --> name2ab
* name1a --> name2ac
* .
* .
* .
* name1b --> name2ba
* name1b --> name2bb
* name1b --> name2bc
* .
* .
* .
*
* For a distinct name1, only the first block of name pairs is valid. A
* graph can be inverted by reversing the relation between name pairs,
* i.e., by putting name2 first:
*
* name2 --> name1
*
* Unless a block contains only a single name pair, then an initial
* name1-name1 pair is effectively ignored. A name1-name1 pair after the
* first represents a cycle - i.e., a node which points to itself. A
* block consisting of a single name1-name1 pair represents a non-cyclic,
* possibly disconnected, node. */
static struct imm_node *imm_tail; /* immediate list tail */
/* Get name pairs from the input, and insert them as arcs to the DCG: an
* arc tail is the head of a linearly linked list (the immediate list) of
* arc heads to which it is connected (logically). */
static void build_dcg(void)
{
char arc_tail[BUF_MAX]; /* line buffer and arc tail name */
char *arc_head; /* arc head name */
char *arc_ref; /* arc reference */
register int connected;
while ((connected = get_arc(arc_tail, &arc_head, &arc_ref)) != -1)
if (!connected)
imm_tail = create_arc_node(arc_tail, arc_ref);
else if (connected && imm_tail)
imm_tail = link_arc_node(arc_head, imm_tail);
else
fprintf(stderr, "%s: cannot redefine: %s\n", progname, arc_tail);
}
char tail_name[NAME_MAX] = ""; /* previous arc tail name */
/* Read from stdin a name pair and a reference in the form
* `name1<tab>name2<tab>reference<newline>.' Return 1 if the tail of arc
* name1 --> name2 (i.e., name1) is the tail the previous arc,
* otherwise 0. */
get_arc(char *buf, char **ip, char **rp)
{
/* line read and data format okay */
if (fgets(buf, BUF_MAX, stdin) != NULL
&& (*ip = strchr(buf, '\t')) != NULL
&& (*rp = strchr(*ip + 1, '\t')) != NULL) {
/* null-terminate name1 and name2 substrings */
*(*rp)++ = *(*ip)++ = '\0';
/* arc tail not previous tail */
if (strcmp(buf, tail_name)) {
/* update arc tail name */
strcpy(tail_name, buf);
/* name pair is an arc (as opposed to a node) */
if (strcmp(buf, *ip)) {
/* create an arc tail node */
imm_tail = create_arc_node(buf, *rp);
/* arc */
return 1;
}
/* node */
return 0;
}
/* arc */
return 1;
}
/* eof */
return -1;
}
/* Given a name (s), if it is not already on the name list, create a node
* for it there. Otherwise, retrieve the name list node. Create an arc
* tail (i.e., imm_list) node and link it to the new/retrieved name
* node (via the name node's imm_list pointer). Return a pointer to the
* arc tail node. */
struct imm_node *
create_arc_node(char *s, char *t)
{
struct name_node *np;
struct imm_node *ip;
/* name already on name list */
if (np = nlist_contains(s)) {
/* arc tail node installed && arc reference realloc'd */
if ((ip = node_to_arc(np, (struct imm_node *) 0)) != 0
&& (np->imm_ref = realloc(np->imm_ref, strlen(t) + 1)) != NULL) {
/* update arc reference */
strcpy(np->imm_ref, t);
return ip;
}
return (struct imm_node *) 0;
}
/* add name to name list and install arc tail node */
return node_to_arc(name_to_nlist(s, t), (struct imm_node *) 0);
}
char *nil = " "; /* should be "", but 386BSD 0.1 bus errors XXX */
/* Given a name (s), if it is not already on the name list, create a node
* for it there. Otherwise, retrieve the name list node. Create an arc
* head (i.e., imm_list) node and link it to the tail of the current
* immediate list. Return a pointer to the arc head node. */
struct imm_node *
link_arc_node(char *s, struct imm_node *tail)
{
register struct name_node *p;
register struct imm_node *ip = 0;
/* (name already on name list or added name) and installed new arc
* and name != arc tail's name */
if (((p = nlist_contains(s)) != 0 || (p = name_to_nlist(s, nil)) != 0)
&& (ip = node_to_arc(p, tail)) != 0 && strcmp(s, tail_name))
p->is_arc_